#!/usr/bin/env python2
# coding: utf-8


import unittest
import threading

from zstack import Client
from zstack.controller import system
from zstack.controller import network
from zstack.controller import vm

ADMIN_USERNAME = 'admin'
ADMIN_PASSWORD = 'password'
ZSTACK_API_URL = 'http://192.168.1.115:8080/zstack/api'
IMAGE_UUID = '8fb4cffd2dc142ef9c3204ed32d88656'
NIC = 'enp3s0'
ZSTACK_NET_SERVICES = None
CLUSTER_UUID = None
ZONE_UUID = None
PUBLIC_NETWORK = None
VROUTER_IMAGE_UUID = None

# 安全组及规则测试使用到的参数
SECURITY_TYPE = 'Ingress'
PROTOCOL = 'TCP'
# START_PORT = 65535
START_PORT = 16
END_PORT = 65535
L3_NETWORK_UUID = 'c88169cc00864306b00becf33b9d7f20'


class TestNetwork(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.client = Client(ADMIN_USERNAME, ADMIN_PASSWORD, ZSTACK_API_URL)
        cls.client.login()
        config = system.environment_variables_init(cls.client)
        global ZSTACK_NET_SERVICES, CLUSTER_UUID, ZONE_UUID, PUBLIC_NETWORK, VROUTER_IMAGE_UUID, IMAGE_UUID
        ZSTACK_NET_SERVICES = config.get('services') if not ZSTACK_NET_SERVICES else ZSTACK_NET_SERVICES
        CLUSTER_UUID = config.get('cluster_uuid') if not CLUSTER_UUID else CLUSTER_UUID
        ZONE_UUID = config.get('zone_uuid') if not ZONE_UUID else ZONE_UUID
        PUBLIC_NETWORK = config.get('no_vlan_l3_network_uuid') if not PUBLIC_NETWORK else PUBLIC_NETWORK
        VROUTER_IMAGE_UUID = config.get('vrouter_image_uuid') if not VROUTER_IMAGE_UUID else VROUTER_IMAGE_UUID
        IMAGE_UUID = VROUTER_IMAGE_UUID if not IMAGE_UUID else IMAGE_UUID

    # 创建、查询、销毁一个扁平网络
    def test_flat_network(self):
        # 创建
        net_mutex = threading.Lock()
        l3_network_uuid = network.create_network(
            self.client, net_mutex, u'test Flat', '200.' + '.'.join([str(200)] * 2) + '.0/24', NIC,
            'Flat',
            services=ZSTACK_NET_SERVICES, cluster_uuid=CLUSTER_UUID, zone_uuid=ZONE_UUID, async=False)

        # 查询
        l3_networks_uuid = [l3_network.get('uuid') for l3_network in network.query_l3_network(self.client)]
        self.assertIn(l3_network_uuid, l3_networks_uuid)

        # 销毁
        network.destroy_l3_network(self.client, l3_network_uuid)

        # 查询
        l3_networks_uuid = [l3_network.get('uuid') for l3_network in network.query_l3_network(self.client)]
        self.assertNotIn(l3_network_uuid, l3_networks_uuid)

    # 创建、查询、销毁一个云路由网络
    def test_vrouter_network(self):
        # 在公共网络（PUBLIC_NETWORK）下创建一个C1-M1G云路由规格
        vrouter_instance_offering_uuid = network.create_virtual_router_template(
            self.client, 'test-vrouter-instance', PUBLIC_NETWORK, VROUTER_IMAGE_UUID, ZONE_UUID).get('uuid')

        # 创建
        net_mutex = threading.Lock()
        l3_network_uuid = network.create_network(
            self.client, net_mutex, u'test vrouter', '200.' + '.'.join([str(200)] * 2) + '.0/24', NIC,
            'vrouter', resource_uuid=vrouter_instance_offering_uuid,
            services=ZSTACK_NET_SERVICES, cluster_uuid=CLUSTER_UUID, zone_uuid=ZONE_UUID, async=False)

        # 查询
        l3_networks_uuid = [l3_network.get('uuid') for l3_network in network.query_l3_network(self.client)]
        self.assertIn(l3_network_uuid, l3_networks_uuid)

        # 销毁
        network.destroy_l3_network(self.client, l3_network_uuid)

        # 销毁云路由规格
        vm.delete_instance_offering(self.client, vrouter_instance_offering_uuid)
        self.assertEqual(vm.query_instance_offering_by_uuid(self.client, vrouter_instance_offering_uuid), [])

        # 查询
        l3_networks_uuid = [l3_network.get('uuid') for l3_network in network.query_l3_network(self.client)]
        self.assertNotIn(l3_network_uuid, l3_networks_uuid)

    # 该测试接口包括测试以下内容：创建安全组、查询安全组、添加安全组规则、查询l3网络、将安全组与l3网络attach、删除安全组
    def test_security_group_and_rule(self):
        group = network.create_security_group(self.client, 'py_name01', 'py_description01')
        self.assertEqual(group['name'], 'py_name01')
        self.assertEqual(group['description'], 'py_description01')

        # 在安全组列表中查询该安全组
        self.assertIn(group['uuid'], [group.get('uuid') for group in network.query_security_group(self.client)])

        # 查询该安全组
        group1 = network.query_security_group_by_uuid(self.client, group['uuid'])
        self.assertIsNotNone(group1)

        # 添加安全规则(返回的rule仍然为安全组的返回json，只是该json中包含了安全rule)
        group2 = network.add_security_group_rule(
            self.client, SECURITY_TYPE, PROTOCOL, START_PORT, END_PORT, group['uuid'])
        rules = group2['rules']
        self.assertIn(SECURITY_TYPE, [rule.get('type') for rule in rules])
        self.assertIn(PROTOCOL, [rule.get('protocol') for rule in rules])
        self.assertIn(START_PORT, [rule.get('startPort') for rule in rules])
        self.assertIn(END_PORT, [rule.get('endPort') for rule in rules])

        # 查询l3网络(前面已有测试用例，此处跳过)
        nets = network.query_l3_network(self.client)

        for net in nets[:3]:
            # 将安全组绑定到l3网络
            group3 = network.attach_security_group_to_l3_network(self.client, net['uuid'], group['uuid'])
            # net['uuid']是否已经添加到安全组中
            attached_l3_network_uuids = group3['attachedL3NetworkUuids']
            self.assertIn(net['uuid'], attached_l3_network_uuids)
            # 将安全组与l3网络解绑
            group4 = network.detach_security_group_from_l3_network(self.client, net['uuid'], group['uuid'])
            attached_l3_network_uuids = group4['attachedL3NetworkUuids']
            self.assertNotIn(net['uuid'], attached_l3_network_uuids)

        # 删除安全组
        network.delete_security_group(self.client, group['uuid'])
        group5 = network.query_security_group_by_uuid(self.client, group['uuid'])
        self.assertEqual(group5, [])


if __name__ == '__main__':
    unittest.main()
